using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

using System.Xml;
using Office = Microsoft.Office.Core;

using LogAnalyzerIIS.Helpers;

namespace LogAnalyzerIIS.Objects
{
	/// <summary>
	///  Encapsulates session
	/// </summary>
	public class Session
	{
		/// <summary>
		/// session name
		/// </summary>
		public string Name = "Untitled";

		/// <summary>
		/// folder to store session log files 
		/// </summary>
		public string DownloadFolder = "";

		/// <summary>
		/// folder to store session output files 
		/// </summary>
		public string OutputFolder = "";

		/// <summary>
		/// the name of file where session properties have been stored 
		/// </summary>
		public string SaveLocation = "";

		/// <summary>
		/// indicated whether server-side logs should be deleted 
		/// </summary>
		public bool ClearServerLogFiles;

		/// <summary>
		/// indicates whether downloaded logs should be deleted
		/// </summary>
		public bool ClearDownloadedLogFiles;

		/// <summary>
		/// list of session servers
		/// </summary>
		public List<ServerRecord> ServerRecords;

		/// <summary>
		/// list of session output files
		/// </summary>
		public List<FilePath> ReportFilepaths;

		/// <summary>
		/// Initializes new session object
		/// </summary>
		public Session()
		{
			ServerRecords = new List<ServerRecord>();
			ReportFilepaths = new List<FilePath>();
		}

		public override string ToString()
		{
			return Name;
		}

		/// <summary>
		/// Loads session properties from the XML file.
		/// </summary>
		/// <param name="path">Path to the session properties file to load from.</param>
		/// <returns>Returns true if succeed</returns>
		public bool LoadSessionFromFile(string path)
		{
			XmlTextReader Reader = new XmlTextReader(path);

			// read the normal attributes
			if (Reader.ReadToFollowing("Common"))
			{
				if (Reader.ReadToDescendant("Name") && !Reader.IsEmptyElement)
					this.Name = Reader.ReadElementContentAsString();

				if (Reader.ReadToNextSibling("DownloadFolder") && !Reader.IsEmptyElement)
					this.DownloadFolder = Reader.ReadElementContentAsString();

				if (Reader.ReadToNextSibling("OutputFolder") && !Reader.IsEmptyElement)
					this.OutputFolder = Reader.ReadElementContentAsString();

				if (Reader.ReadToNextSibling("ClearServer") && !Reader.IsEmptyElement)
					this.ClearServerLogFiles = Reader.ReadElementContentAsString().Equals(System.Boolean.TrueString);

				if (Reader.ReadToNextSibling("ClearDownloaded") && !Reader.IsEmptyElement)
					this.ClearDownloadedLogFiles = Reader.ReadElementContentAsString().Equals(System.Boolean.TrueString);
			}

			// now read the server records
			if (Reader.ReadToFollowing("Server"))
			{
				do
				{
					ServerRecord server = new ServerRecord();

					// get name of the server
					if (Reader.ReadToDescendant("Name") && !Reader.IsEmptyElement)
						server.Name = Reader.ReadElementContentAsString();

					// get path of the server
					if (Reader.ReadToNextSibling("Path") && !Reader.IsEmptyElement)
						server.Path = Reader.ReadElementContentAsString();

					// get server alias
					if (Reader.ReadToNextSibling("Alias") && !Reader.IsEmptyElement)
						server.Alias = Reader.ReadElementContentAsString();

					// get username for accessing the server
					if (Reader.ReadToNextSibling("Username") && !Reader.IsEmptyElement)
						server.Username = (new EncryptionHelper()).DecryptString(Reader.ReadElementContentAsString());

					// get password for accessing the server
					if (Reader.ReadToNextSibling("Password") && !Reader.IsEmptyElement)
						server.Password = (new EncryptionHelper()).DecryptString(Reader.ReadElementContentAsString());

					// get value indicating whether server needs to be processed
					if (Reader.ReadToNextSibling("InUse") && !Reader.IsEmptyElement)
						server.Enabled = Reader.ReadElementContentAsString().Equals(System.Boolean.TrueString);

					// read applications associated to the server
					if (Reader.ReadToNextSibling("WebApplications") && !Reader.IsEmptyElement)
					{
						if (Reader.ReadToDescendant("WebApplication") && !Reader.IsEmptyElement)
						{
							do
							{
								WebApplication webApplication = new WebApplication();

								// get application name
								if (Reader.ReadToDescendant("Name") && !Reader.IsEmptyElement)
									webApplication.Name = Reader.ReadElementContentAsString();

								// get path to the application log files
								if (Reader.ReadToNextSibling("LogPath") && !Reader.IsEmptyElement)
									webApplication.LogPath = Reader.ReadElementContentAsString();

								// get the start date of application logs
								if (Reader.ReadToNextSibling("StartDate") && !Reader.IsEmptyElement)
								{
									try
									{
										webApplication.StartDate = Convert.ToDateTime(Reader.ReadElementContentAsString());
									}
									catch
									{
										webApplication.StartDate = DateTime.MaxValue;
									}
								}

								// get the end date of the application logs
								if (Reader.ReadToNextSibling("EndDate") && !Reader.IsEmptyElement)
								{
									try
									{
										webApplication.EndDate = Convert.ToDateTime(Reader.ReadElementContentAsString());
									}
									catch
									{
										webApplication.EndDate = DateTime.MinValue;
									}
								}

								// get value indicatinge whether the application needs to be processed
								if (Reader.ReadToNextSibling("InUse") && !Reader.IsEmptyElement)
									webApplication.Enabled = Reader.ReadElementContentAsString().Equals(Boolean.TrueString);

								// get paths to the application log files
								if (Reader.ReadToNextSibling("LogFiles") && !Reader.IsEmptyElement)
								{
									if (Reader.ReadToDescendant("LogFile") && !Reader.IsEmptyElement)
										webApplication.LogFiles.Add(new FilePath(Reader.ReadElementContentAsString()));
								}

								while (Reader.ReadToNextSibling("LogFile") && !Reader.IsEmptyElement)
									webApplication.LogFiles.Add(new FilePath(Reader.ReadElementContentAsString()));

								server.WebApplications.Add(webApplication);

								while (!(Reader.NodeType == XmlNodeType.EndElement && Reader.Name == "WebApplication"))
									Reader.Skip();

							}
							while (Reader.ReadToNextSibling("WebApplication"));
						}
					}

					ServerRecords.Add(server);

					while (!(Reader.NodeType == XmlNodeType.EndElement && Reader.Name == "Server"))
						Reader.Skip();
				}
				while (Reader.ReadToNextSibling("Server"));

				// read the output files paths
				if (Reader.ReadToNextSibling("OutputFiles") && !Reader.IsEmptyElement)
				{
					if (Reader.ReadToDescendant("OutputFile") && !Reader.IsEmptyElement)
					{
						do
						{
							ReportFilepaths.Add(new FilePath(Reader.ReadElementContentAsString()));
						}
						while (Reader.ReadToNextSibling("OutputFile"));
					}
				}
			}

			Reader.Close();

			SaveLocation = path;

			return true;
		}

		/// <summary>
		/// Saves the session properties an XML file
		/// </summary>
		/// <param name="path">Path of the output XML file</param>
		public void Save()
		{
			StreamWriter OutFile = new StreamWriter(this.SaveLocation, false, Encoding.Unicode);

			XmlTextWriter Writer = new XmlTextWriter(OutFile);
			Writer.Formatting = Formatting.Indented;

			// write start document
			Writer.WriteStartDocument();

			// write root element
			Writer.WriteStartElement("Session");

			// write common properties element
			Writer.WriteStartElement("Common");

			// write session name
			Writer.WriteElementString("Name", this.Name);

			// write path to session download folder
			Writer.WriteElementString("DownloadFolder", this.DownloadFolder);

			// write path to session output folder
			Writer.WriteElementString("OutputFolder", this.OutputFolder);

			// write value indicating whether log files on the server should be deleted
			Writer.WriteElementString("ClearServer", this.ClearServerLogFiles.ToString());

			// write value indicating whether downloaded log files should be deleted
			Writer.WriteElementString("ClearDownloaded", this.ClearDownloadedLogFiles.ToString());

			Writer.WriteEndElement();

			// write the servers
			Writer.WriteStartElement("Servers");

			foreach (ServerRecord server in ServerRecords)
			{
				// write server element
				Writer.WriteStartElement("Server");

				// write server name
				Writer.WriteElementString("Name", server.Name);

				// write path to server log files
				Writer.WriteElementString("Path", server.Path);

				// write server alias
				Writer.WriteElementString("Alias", server.Alias);

				// write username to access the server
				Writer.WriteElementString("Username", (new EncryptionHelper()).EncryptString(server.Username));

				// write password to access the server
				Writer.WriteElementString("Password", (new EncryptionHelper()).EncryptString(server.Password));

				// write value indicating whether server needs to be processed
				Writer.WriteElementString("InUse", server.Enabled.ToString());

				// write applications element
				Writer.WriteStartElement("WebApplications");

				foreach (WebApplication wa in server.WebApplications)
				{
					// writ application element
					Writer.WriteStartElement("WebApplication");

					// write application name
					Writer.WriteElementString("Name", wa.Name);

					// write path to application log files
					Writer.WriteElementString("LogPath", wa.LogPath);

					// write start date of application log files
					Writer.WriteElementString("StartDate", wa.StartDate.Date.ToString());

					// write end date of application log files
					Writer.WriteElementString("EndDate", wa.EndDate.Date.ToString());

					// write value indicating whether application needs to be processed
					Writer.WriteElementString("InUse", wa.Enabled.ToString());

					// write log files element
					Writer.WriteStartElement("LogFiles");

					// write paths to application log files
					foreach (FilePath f in wa.LogFiles)
						Writer.WriteElementString("LogFile", f.FullPath);

					Writer.WriteEndElement();
					Writer.WriteEndElement();
				}

				Writer.WriteEndElement();
				Writer.WriteEndElement();
			}

			Writer.WriteEndElement();

			// write the output files
			Writer.WriteStartElement("OutputFiles");

			// write path to appliaciton output files
			foreach (FilePath fp in this.ReportFilepaths)
				Writer.WriteElementString("OutputFile", fp.FullPath);

			Writer.WriteEndElement();
			Writer.WriteEndElement();
			Writer.WriteEndDocument();

			Writer.Flush();
			OutFile.Flush();
			OutFile.Close();
		}
	}

	/// <summary>
	/// Represents a file path
	/// </summary>
	public class FilePath
	{
		public string FullPath;

		public FilePath(string path)
		{
			FullPath = path;
		}

		public override string ToString()
		{
			return Path.GetFileName(FullPath);
		}
	}
}